<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      let obj = { name: "姚思远", age: 18 };
      const map = new Map([
        ["key1", "value1"],
        ["key2", "value2"],
        ["key3", "value3"],
        [obj, "帅哥"],
      ]);
      const obj1 = {
        a: 1,
        b: {
          c: 2,
          d: [3, 4],
        },
        f: map,
      };

      function deepClone(target) {
        function _deepClone(target, hash) {
          // 1.原始数据类型和function,直接返回
          if (typeof target !== "object" || target === null) {
            return target;
          }

          // 将已克隆的属性存储起来，第二次克隆时，直接返回即可
          if (hash.has(target)) {
            return hash.get(target);
          }

           // 如果是 Date 或 RegExp，直接使用构造函数克隆
          if (target instanceof Date) {
            return new Date(target);
          }
          if (target instanceof RegExp) {
            return new RegExp(target);
          }

          // 如果是Map或者set结构，直接使用对应的构造函数进行深度克隆
          if (target instanceof Map) {
            const cloneMap = new Map();
            hash.set(target, cloneMap);
            target.forEach((value, key) => {
              cloneMap.set(_deepClone(key, hash), _deepClone(value, hash));
            });
            return cloneMap;
          }

          if (target instanceof Set) {
            const cloneSet = new Set();
            hash.set(target, cloneSet);
            target.forEach((value) => {
              cloneSet.add(_deepClone(value, hash));
            });
            return cloneSet;
          }

          // 对象或者数组
          const cloneTarget = Array.isArray(target) ? [] : {};

          // 将当前对象存储到 hash 中
          hash.set(target, cloneTarget);

          for (let key in target) {
            if (target.hasOwnProperty(key)) {
              cloneTarget[key] = _deepClone(target[key], hash);
            }
          }
          return cloneTarget;
        }

        return _deepClone(target, new WeakMap());
      }

      // 检测循环引用是否被处理了
      obj1.e = obj1;

      const obj2 = deepClone(obj1);

      console.log("obj1", obj1);
      console.log("obj2", obj2);
      obj1.a = "hah";
      obj1.b.d.push("hahah");
      obj1.f.set("key4", "value4");
      console.log("obj2", obj2);
    </script>
  </body>
</html>
